package sma.agents;

import javax.swing.JComponent;
import javax.swing.JLayeredPane;

import ihm.AppliWindow;

import org.janusproject.kernel.address.Address;
import org.janusproject.kernel.address.AgentAddress;
import org.janusproject.kernel.agent.Agent;
import org.janusproject.kernel.agentmemory.Memory;
import org.janusproject.kernel.agentsignal.QueuedSignalAdapter;
import org.janusproject.kernel.status.Status;
import org.janusproject.kernel.status.StatusFactory;

import appli.utils.Config;

import sma.agents.bodies.CircleBody;
import sma.agents.bodies.DecisiveAgentBody;
import sma.agents.channels.GuiChannel;
import sma.agents.listeners.DeleteListener;
import sma.agents.listeners.MoveListener;
import sma.organizations.signals.SendDeleteAgentSignal;
import sma.organizations.signals.SendMoveGoalSignal;
import sma.organizations.signals.SendMoveSignal;

/**
 * StandartAgent est l'agent type dont vont decouler tous les autres, il nous
 * fournit des methodes utilisees par l'ihm par exemple.
 * 
 * @author Etienne
 * @version 0.1
 */
public abstract class StandartAgent extends Agent {
	/**
	 * 
	 * L'environnement dans lequel l'agent evolue
	 * 
	 */
	protected sma.environment.LocalEnvironment environment;

	/**
	 * 
	 * Le body de l'agent
	 * 
	 */
	protected sma.agents.bodies.CircleBody body;

	/**
	 * La mémoire de l'agent
	 * 
	 * @see Memory
	 */
	protected Memory memory;

	/** 
	 * Le channel de discussion avec la GUI
	 */
	protected GuiChannelImpl guiChannel;
	
	/**
	 * Groupe de l'agent (correspondant à un télémètre)
	 */
	protected int groupe;
	
	/**
	 * Create a local listener on the signals coming from the role itself.
	 */
	protected QueuedSignalAdapter<SendMoveSignal> privateMoveSignals = new QueuedSignalAdapter<SendMoveSignal>(SendMoveSignal.class);
	
	/**
	 * Create a local listener on the signals coming from the role itself.
	 */
	protected QueuedSignalAdapter<SendDeleteAgentSignal> privateDeleteSignals = new QueuedSignalAdapter<SendDeleteAgentSignal>(SendDeleteAgentSignal.class);
	
	
	/**
	 * Initialisation standart
	 * @param parameters l'ihm, la seule chose obligatoire, elle permettra d'impl�manter le channel
	 */
	public void init(JComponent parameters) {
		guiChannel = new GuiChannelImpl();
		guiChannel.addMoveListener((MoveListener) parameters);
		guiChannel.addDeleteListener((DeleteListener) parameters);
		
		getSignalEmitter().addSignalListener(this.privateMoveSignals);
		getSignalEmitter().addSignalListener(this.privateDeleteSignals);
	}
	
	@Override
	public Status live() {
		super.live();
		// Recuperons les derniers mouvements en memoire
		{
			SendMoveSignal sig;
			sig = this.privateMoveSignals.getFirstAvailableSignal();
			while (sig != null) {
				guiChannel.move(getAddress(), getBody());
				sig = this.privateMoveSignals.getFirstAvailableSignal();
			}
			
			SendDeleteAgentSignal sigDelete;
			sigDelete = this.privateDeleteSignals.getFirstAvailableSignal();
			while (sigDelete != null) {
				//A laisser avant le Kill me
				guiChannel.onDeleteAgent(getAddress());
				
				this.killMe();
			
				sigDelete = this.privateDeleteSignals.getFirstAvailableSignal();
			}
			
			
		}
		return StatusFactory.ok(this);
	}
	
	/**
	 * Mort de l'agent
	 */
	@Override
	public Status end() {
		guiChannel.onDeleteAgent(getAddress());
		
		if (Config.DEBUG == true)
			print("Je suis mort....");
		
		super.end();
		return StatusFactory.ok(this);
	}
	
	/**
	 * 
	 * @return CircleBody
	 */
	public sma.agents.bodies.CircleBody getBody() {
		return this.body;
	}

	/**
	 * @return the guiChannel
	 */
	public GuiChannelImpl getGuiChannel() {
		return guiChannel;
	}
	
	/**
	 * 
	 * @author Etienne Sainton
	 *
	 */
	public class GuiChannelImpl implements GuiChannel {

		@Override
		public void addMoveListener(MoveListener listener) {
			StandartAgent.this.addEventListener(MoveListener.class, listener);			
		}

		@Override
		public void addDeleteListener(DeleteListener listener) {
			StandartAgent.this.addEventListener(DeleteListener.class, listener);			
		}


		@Override
		public void removeDeleteListener(DeleteListener listener) {
			StandartAgent.this.removeEventListener(DeleteListener.class, listener);
			
		}
		

		@Override
		public void removeMoveListener(MoveListener listener) {
			StandartAgent.this.removeEventListener(MoveListener.class, listener);
		}

		@Override
		public Address getChannelOwner() {
			return getAddress();
		}

		@Override
		public void move(AgentAddress adress, CircleBody body) {
			
			

			MoveListener[] list = getEventListeners(MoveListener.class);
			
			for (MoveListener listener : list) {
	        	try {
	        		listener.onMoveAgent(getAddress(), getBody(), groupe);
	        	} catch (Error e) {
	        		System.out.println("Erreur : "+e);
	        	}
	        }	
    		
            	
		}

		@Override
		public void onDeleteAgent(AgentAddress adress) {
			
			MoveListener[] listMove = getEventListeners(MoveListener.class);

            for (MoveListener listener : listMove) {
            	removeMoveListener(listener);
            }	
            
            DeleteListener[] listDelete = getEventListeners(DeleteListener.class);

            for (DeleteListener listener : listDelete) {
            	listener.onDeleteAgent(getAddress(), groupe);
            	//removeDeleteListener(listener);
            }
			
		}

		@Override
		public void deleteAgent() {
			fireSignal(new SendDeleteAgentSignal(this));
		}


	}

}
